//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.UIDesigner.Monitor
{
    using System;
    using System.Collections.ObjectModel;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.Commands;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
    using Microsoft.Practices.Unity;
    using Microsoft.Research.eResearch.Blackboard.Common;
    using Microsoft.Research.eResearch.Subscriber.Interfaces;
    using System.Collections.Generic;
    using System.Globalization;

    public class ProcessingStatusPresentationModel
    {
        private Dictionary<string, int> iterationDictionary = new Dictionary<string, int>();

        public ProcessingStatusView View { get; private set; }

        public ObservableCollection<ProcessingStatus> ProcessingStatusCollection { get; private set; }

        public ProcessingStatusPresentationModel(IUnityContainer container, ProcessingStatusView view, JobCommandProxy jobCommandProxy)
        {
            this.View = view;
            this.ProcessingStatusCollection = new ObservableCollection<ProcessingStatus>();

            container.Resolve<IMonitorService>().WorkflowInstanceCreated += delegate { this.ProcessingStatusCollection.Clear(); };
            container.Resolve<IMonitorService>().WorkflowMessage += OnProcessingStatusRecieved;
            container.Resolve<IMonitorService>().ActivityMessage += OnProcessingStatusRecieved;
            container.Resolve<IMonitorService>().IterationEvent += OnIterationMessageReceived;
            container.Resolve<IMonitorService>().Clear += delegate { this.ProcessingStatusCollection.Clear(); this.iterationDictionary.Clear(); };
            jobCommandProxy.ExecuteCommand.RegisterCommand(new DelegateCommand<object>(p => { this.ProcessingStatusCollection.Clear(); this.iterationDictionary.Clear(); }));

            this.View.Model = this;
        }

        private void OnProcessingStatusRecieved(object sender, BlackboardMessageReceivedEventArgs e)
        {
            BlackboardMessage message = e.IncomingMessage;
            ProcessingStatus status = new ProcessingStatus
            {
                Details = string.Empty
            };

            DateTime executionTime;
            try
            {
                executionTime = new DateTime(long.Parse(e.IncomingMessage["time:DateTimeDescription"], CultureInfo.InvariantCulture));
                status.Time = TimeZone.CurrentTimeZone.ToLocalTime(executionTime);
            }
            catch (FormatException)
            {
                //Ignore. 
            }
            catch (ArgumentNullException)
            {
                //Ignore. 
            }
            catch (OverflowException)
            {
                //Ignore. 
            }

            if (IsActivityEvent(message))
            {
                status.Activity = message["trident:ActivityLabel"];
                status.Event = message["trident:ActivityState"];

                // If the iterating activity closes then remove it from the dictionary.
                if (status.Event.Equals("Closed"))
                {
                    if (this.iterationDictionary.ContainsKey(message["trident:ActivityName"]))
                    {
                        this.iterationDictionary.Remove(message["trident:ActivityName"]);
                    }
                }
            }

            if (IsWorkflowEvent(message))
            {
                status.Activity = message["trident:WorkflowName"];
                status.Event = message["trident:WorkflowState"];

                if (message.ContainsKey("trident:ExceptionDetails"))
                {
                    status.Details = message["trident:ExceptionDetails"];
                }
            }

            ProcessingStatusCollection.Add(status);
        }

        private void OnIterationMessageReceived(object sender, BlackboardMessageReceivedEventArgs e)
        {
            ProcessingStatus status = new ProcessingStatus
            {
                Details = string.Empty
            };

            DateTime executionTime;
            try
            {
                executionTime = new DateTime(long.Parse(e.IncomingMessage["time:DateTimeDescription"], CultureInfo.InvariantCulture));
                status.Time = TimeZone.CurrentTimeZone.ToLocalTime(executionTime);
            }
            catch (FormatException)
            {
                //Ignore. 
            }
            catch (ArgumentNullException)
            {
                //Ignore. 
            }
            catch (OverflowException)
            {
                //Ignore. 
            }

            string activityUniqueName = e.IncomingMessage["trident:ActivityName"];
            if (!this.iterationDictionary.ContainsKey(activityUniqueName))
            {
                this.iterationDictionary.Add(activityUniqueName, 1);
            }
            else
            {
                this.iterationDictionary[activityUniqueName]++;
            }
            status.Activity = e.IncomingMessage["trident:ActivityLabel"];
            status.Event = "Iteration: " + this.iterationDictionary[activityUniqueName].ToString(CultureInfo.InvariantCulture) +
                ", Value: " + e.IncomingMessage["trident:IterationValue"];

            ProcessingStatusCollection.Add(status);
        }

        private static bool IsActivityEvent(BlackboardMessage message)
        {
            return message.ContainsKey("trident:ActivityState");
        }

        private static bool IsWorkflowEvent(BlackboardMessage message)
        {
            return message.ContainsKey("trident:WorkflowState");
        }
    }
}
